package cn.frh.user.service.impl;

import cn.frh.basic.constant.BaseConstants;
import cn.frh.basic.exception.BusinessException;
import cn.frh.basic.util.AjaxResult;
import cn.frh.basic.util.HttpClientUtils;
import cn.frh.basic.util.MD5Utils;
import cn.frh.basic.util.StrUtils;
import cn.frh.user.domain.Logininfo;
import cn.frh.user.domain.User;
import cn.frh.user.domain.WxUser;
import cn.frh.user.dto.LoginDto;
import cn.frh.user.dto.UserDto;
import cn.frh.user.mapper.LogininfoMapper;
import cn.frh.user.mapper.UserMapper;
import cn.frh.user.mapper.WxUserMapper;
import cn.frh.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.xml.crypto.Data;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String, Object> acountLogin(LoginDto dto) {
        //1效验
        if (dto.getType()==null ||dto.getUsername() == null ||dto.getPassword() == null){
            throw new BusinessException("必要参数不能为空");
        }
        //2根据用户名查询数据库t_logininfo
        Logininfo logininfo = logininfoMapper.loadByUserName(dto);
        //2.1查询不到 报错
        if (logininfo == null){
            throw new BusinessException("用户不存在");
        }
        //2.2查询到了比对密码是否一致（加密之后的密码
        String salt = logininfo.getSalt();
        String md5Pwd = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if (!logininfo.getPassword().equals(md5Pwd)){
            throw new BusinessException("账户名或密码错误");
        }
        //3登录成功
        String token = UUID.randomUUID().toString();
        //保存redis
        redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
        //返回登陆成功后的必要信息
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //将密码和盐值设为null
        logininfo.setPassword(null);
        logininfo.setSalt(null);
        map.put("logininfo",logininfo);
        return map;
    }

    @Override
    public AjaxResult wechat(String code) {
        //空校验(可以不做空校验）
        if (StringUtils.isEmpty(code)){
            throw new BusinessException("必要参数不能为空");
        }
        //根据code从微信获取token和openId
        String tokenUrl = BaseConstants.GET_TOKEN_URL
                .replace("APPID", BaseConstants.APPID)
                .replace("SECRET", BaseConstants.SECRET)
                .replace("CODE", code);
        //调用工具类发送请求
        String tokenObjStr = HttpClientUtils.httpGet(tokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(tokenObjStr);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        //通过openId去查询t_wxuser
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if (wxUser !=null && wxUser.getUser_id()!=null){
            //之前已经扫码过了
            Logininfo logininfo = logininfoMapper.loadByUserId(wxUser.getUser_id());
            //免密登录
            String token = UUID.randomUUID().toString();
            //存入redis
            redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
            //返回登陆成功后的必要信息
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            //将密码和盐值设为null
            logininfo.setPassword(null);
            logininfo.setSalt(null);
            map.put("logininfo",logininfo);
            return AjaxResult.me().setResultObj(map);
        }else {
            String binderParams = "?accessToken="+accessToken+"&openId="+openId;
            return AjaxResult.me().setSuccess(false).setResultObj(binderParams);
        }
    }

    @Override
    public Map<String, Object> binderWechat(Map<String, String> params) {

        String phone = params.get("phone");
        String verifyCode  = params.get("verifyCode");
        String accessToken  = params.get("accessToken");
        String openId  = params.get("openId");
        //空校验
        if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)){
            throw new BusinessException("参数不能为空");
        }
        //效验验证码
        // 4.判断验证码是否过期
        Object codeTmp = redisTemplate.opsForValue().get(BaseConstants.BUSINESS_BINDER_PREFIX + phone);
        if (codeTmp==null){
            throw new BusinessException("验证码已过期，请重新获取");
        }
        // 2.验证码是否正确
        String code = ((String)codeTmp).split(":")[0];
        if(!verifyCode.equalsIgnoreCase(code)){//比对验证码不要区分大小写
            throw new BusinessException("验证码错误!!!");
        }
        //查询手机号是否被注册
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if (user!=null){//如果已经注册过了 就直接绑定
            logininfo = logininfoMapper.loadById(user.getLogininfo_id());
        }else {//如果没有注册过 就直接生成新的
            user = initUser(phone);
            logininfo = userDto2Logininfo(user);
            logininfoMapper.save(logininfo);
            //设置logininfo的id
            user.setLogininfo_id(logininfo.getId());
            userMapper.save(user);
        }
            String getWxUserURL  = BaseConstants.GET_WXUSER_URL
                    .replace("ACCESS_TOKEN", accessToken)
                    .replace("OPENID", openId);
            String wxUserStr = HttpClientUtils.httpGet(getWxUserURL);
            WxUser wxUser = JSONObject.parseObject(wxUserStr, WxUser.class);
            wxUser.setUser_id(user.getId());
            wxUserMapper.save(wxUser);
            //免密登录
            String token = UUID.randomUUID().toString();
            //存入redis
            redisTemplate.opsForValue().set(token,logininfo,30, TimeUnit.MINUTES);
            //返回登陆成功后的必要信息
            Map<String,Object> map = new HashMap<>();
            map.put("token",token);
            //将密码和盐值设为null
            logininfo.setPassword(null);
            logininfo.setSalt(null);
            map.put("logininfo",logininfo);
            return map;
    }

    private Logininfo userDto2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);//前台用户为1 后台0
        return logininfo;
    }

    private User initUser(String phone) {
        //准备返回对象
        User user = new User();
        //设置值
        user.setUsername(phone);
        user.setPhone(phone);
        //设置盐值
        String salt = StrUtils.getComplexRandomString(32);
        //通过盐值加密密码
        String md5Pwd = MD5Utils.encrypByMd5("1" + salt);
        //设置盐值
        user.setSalt(salt);
        //设置密码
        user.setPassword(md5Pwd);
        //返回对象
        return user;
    }
}
